package jxtcp

import (
	"bufio"
	"net"
	"sync"
	"sync/atomic"
	"time"
)

type ClientConn struct {
	conn       net.Conn
	address    string
	static     int32 //0未连接,1:忙碌,2:空闲
	onMessage  func(m *Message)
	stopChan   chan struct{}
	sendLocker sync.Mutex
	writer     *bufio.Writer
	reader     *bufio.Reader
	MachineId  uint32
}

func NewClientConn(address string, mid uint32, f func(m *Message)) *ClientConn {
	outdata := &ClientConn{
		address:   address,
		onMessage: f,
		stopChan:  make(chan struct{}),
		MachineId: mid,
	}
	outdata.Start()
	return outdata
}
func (c *ClientConn) Static() int32 {
	return atomic.LoadInt32(&c.static)
}
func (c *ClientConn) SendMessage(m *Message) bool {
	c.sendLocker.Lock()
	defer c.sendLocker.Unlock()
	if atomic.LoadInt32(&c.static) == 2 {
		go c.sendMessage(m)
		return true
	}
	return false
}
func (c *ClientConn) reconnect() {
	for {
		conn, err := net.Dial("tcp", c.address)
		if err == nil {
			m := NewMessage([]byte("new"))
			m.MachineId = c.MachineId
			m.Type = 10
			c.conn = conn
			c.writer = bufio.NewWriter(conn)
			m.WriteMessage(c.writer)
			c.reader = bufio.NewReader(conn)
			atomic.StoreInt32(&c.static, 2)
			return
		}
		time.Sleep(time.Second * 1)
	}
}
func (c *ClientConn) Start() {
	go c.loop()
}
func (c *ClientConn) loop() {
	for {
		c.reconnect()
		c.readLoop()
	}
}
func (c *ClientConn) sendMessage(m *Message) error {
	atomic.StoreInt32(&c.static, 1)
	defer func() {
		atomic.StoreInt32(&c.static, 2)
	}()
	err := m.WriteMessage(c.writer)
	if err != nil {
		atomic.StoreInt32(&c.static, 0)
		c.stopChan <- struct{}{}
		return err
	}
	return nil
}
func (c *ClientConn) readLoop() {
	for {
		select {
		case <-c.stopChan:
			atomic.StoreInt32(&c.static, 0)
			return
		default:
			message, err := ReadMessage(c.reader)
			if err != nil {
				c.conn.Close()
				c.conn = nil
				return
			}
			if c.onMessage != nil {
				go c.onMessage(message)
			}
		}
	}
}
